 package com.xm.xmds1705083.service.util;


import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class MacUtil 
{
	
	
	
		
		
		/**
		 * 将b1和b2做异或，然后返回
		 * @param b1
		 * @param b2
		 * @return 异或结果
		 */
		public static byte[] xOr(byte[] b1, byte[] b2) 
		{
			byte[] tXor = new byte[Math.min(b1.length, b2.length)];
			for (int i = 0; i < tXor.length; i++)
				tXor[i] = (byte) (b1[i] ^ b2[i]); // 异或(Xor)
			return tXor;
		}
		
		
		/**
		 * des加密算法，ECB方式，NoPadding模式，数据字节必须是8的整数倍
		 * @param key
		 * @param
		 * @return 加密结果
		 * @throws GeneralSecurityException
		 **/
		public static byte[] encryptByDesEcb(byte[] content, byte[] key) throws GeneralSecurityException { 
	        Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");  
	        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey secretKey = keyFactory.generateSecret(new DESKeySpec(key));
	        cipher.init(Cipher.ENCRYPT_MODE, secretKey);  
	        return cipher.doFinal(content);  
	    }

		/**k
		 * ANSI X9.9MAC算法  <br/>
		 * (1) ANSI X9.9MAC算法只使用单倍长密钥。  <br/>
		 * (2)  MAC数据先按8字节分组，表示为D0～Dn，如果Dn不足8字节时，尾部以字节00补齐。 <br/>
		 * (3) 用MAC密钥加密D0，加密结果与D1异或作为下一次的输入。 <br/>
		 * (4) 将上一步的加密结果与下一分组异或，然后再用MAC密钥加密。<br/>
		 * (5) 直至所有分组结束，取最后结果的左半部作为MAC。<br/>
		 * 采用x9.9算法计算MAC (Count MAC by ANSI-x9.9).
		 * 
		 * @param key  8字节密钥数据
		 * @param data 待计算的缓冲区
		 * @throws GeneralSecurityException 
		 */
		public static byte[] calculateANSIX9_9MAC(byte[] key, byte[] data) throws GeneralSecurityException {
			
			final int dataLength = data.length;
			final int lastLength = dataLength % 8;
			final int lastBlockLength = lastLength == 0 ? 8 : lastLength;
			final int blockCount = dataLength / 8 + (lastLength > 0 ? 1 : 0);
			
			// 拆分数据（8字节块/Block）
			byte[][] dataBlock = new byte[blockCount][8];
			for (int i = 0; i < blockCount; i++) 
			{
				int copyLength = ((i == blockCount - 1) ? lastBlockLength : 8);
				System.arraycopy(data, i * 8, dataBlock[i], 0, copyLength);
			}
			
			byte[] desXor = new byte[8];
			for (int i = 0; i < blockCount; i++) {
				byte[] tXor = xOr(desXor, dataBlock[i]);
				desXor = encryptByDesEcb(tXor, key); // DES加密
			}
			return desXor;
		}
		

		

		

}